#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
MCP 高级计算器服务 v2.0

功能特性:
- 基础四则运算
- 高级数学函数（三角函数、对数、指数、统计等）
- 复杂表达式计算
- 单位转换
- 数值分析
- 性能监控
- 结构化日志
- 配置管理
"""

from mcp.server.fastmcp import FastMCP
from typing import Union, List, Dict, Any, Optional
from decimal import Decimal, getcontext
from functools import lru_cache
from dataclasses import dataclass
import math
import statistics
import time
import logging
import json
import os
import re

# 设置高精度计算
getcontext().prec = 50

# 配置日志 - 只输出到文件，不输出到控制台
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('calculator.log', encoding='utf-8')
    ]
)
logger = logging.getLogger('CalculatorMCP')

@dataclass
class CalculatorConfig:
    """计算器配置类"""
    max_expression_length: int = 1000
    max_factorial: int = 170
    precision: int = 15
    enable_cache: bool = True
    log_level: str = "INFO"
    timeout_seconds: float = 30.0
    
    @classmethod
    def from_file(cls, config_path: str = "calculator_config.json"):
        """从配置文件加载配置"""
        if os.path.exists(config_path):
            try:
                with open(config_path, 'r', encoding='utf-8') as f:
                    config_data = json.load(f)
                return cls(**config_data)
            except Exception as e:
                logger.warning(f"加载配置文件失败: {e}，使用默认配置")
        return cls()

class PerformanceMonitor:
    """性能监控类"""
    def __init__(self):
        self.metrics = {
            'total_requests': 0,
            'total_time': 0.0,
            'error_count': 0,
            'function_calls': {}
        }
    
    def record_call(self, function_name: str, execution_time: float, success: bool = True):
        """记录函数调用"""
        self.metrics['total_requests'] += 1
        self.metrics['total_time'] += execution_time
        
        if not success:
            self.metrics['error_count'] += 1
        
        if function_name not in self.metrics['function_calls']:
            self.metrics['function_calls'][function_name] = {
                'count': 0, 'total_time': 0.0, 'errors': 0
            }
        
        self.metrics['function_calls'][function_name]['count'] += 1
        self.metrics['function_calls'][function_name]['total_time'] += execution_time
        if not success:
            self.metrics['function_calls'][function_name]['errors'] += 1
    
    def get_stats(self) -> Dict[str, Any]:
        """获取统计信息"""
        avg_time = self.metrics['total_time'] / max(1, self.metrics['total_requests'])
        error_rate = self.metrics['error_count'] / max(1, self.metrics['total_requests'])
        
        return {
            'total_requests': self.metrics['total_requests'],
            'average_response_time': round(avg_time, 4),
            'error_rate': round(error_rate * 100, 2),
            'function_stats': self.metrics['function_calls']
        }

class ExpressionValidator:
    """表达式验证器"""
    def __init__(self, config: CalculatorConfig):
        self.config = config
        self.allowed_chars = set('0123456789+-*/().,\t\n abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_')
        self.dangerous_patterns = [
            r'__.*__',  # 双下划线属性
            r'import\s+',  # import语句
            r'exec\s*\(',  # exec函数
            r'eval\s*\(',  # eval函数
            r'open\s*\(',  # 文件操作
        ]
    
    def validate(self, expression: str) -> tuple[bool, str]:
        """验证表达式安全性"""
        # 长度检查
        if len(expression) > self.config.max_expression_length:
            return False, f"表达式长度超过限制({self.config.max_expression_length}字符)"
        
        # 字符检查
        if not all(c in self.allowed_chars for c in expression):
            return False, "表达式包含不允许的字符"
        
        # 危险模式检查
        for pattern in self.dangerous_patterns:
            if re.search(pattern, expression, re.IGNORECASE):
                return False, f"表达式包含危险模式: {pattern}"
        
        # 括号平衡检查
        if not self._check_balanced_parentheses(expression):
            return False, "括号不平衡"
        
        return True, "验证通过"
    
    def _check_balanced_parentheses(self, expression: str) -> bool:
        """检查括号是否平衡"""
        count = 0
        for char in expression:
            if char == '(':
                count += 1
            elif char == ')':
                count -= 1
                if count < 0:
                    return False
        return count == 0

# 全局实例
config = CalculatorConfig.from_file()
monitor = PerformanceMonitor()
validator = ExpressionValidator(config)

# 创建MCP服务实例
mcp = FastMCP("Advanced Calculator Server v2.0")

def performance_decorator(func):
    """性能监控装饰器"""
    def wrapper(*args, **kwargs):
        start_time = time.time()
        success = True
        try:
            result = func(*args, **kwargs)
            return result
        except Exception as e:
            success = False
            logger.error(f"函数 {func.__name__} 执行失败: {e}")
            raise
        finally:
            execution_time = time.time() - start_time
            monitor.record_call(func.__name__, execution_time, success)
            # 只记录到日志文件，不输出到控制台
            logger.debug(f"函数 {func.__name__} 执行时间: {execution_time:.4f}秒")
    return wrapper

def validate_number(value: Union[int, float], name: str = "数值") -> Union[int, float]:
    """验证数值有效性"""
    if not isinstance(value, (int, float)):
        raise ValueError(f"{name}必须是数字")
    if math.isnan(value) or math.isinf(value):
        raise ValueError(f"{name}不能是NaN或无穷大")
    return value

# ==================== 基础运算工具 ====================

@mcp.tool()
@performance_decorator
def add(a: float, b: float) -> str:
    """加法运算
    
    Args:
        a: 第一个数字
        b: 第二个数字
        
    Returns:
        加法运算结果
    """
    try:
        validate_number(a, "第一个数")
        validate_number(b, "第二个数")
        
        # 使用Decimal进行高精度计算
        result = float(Decimal(str(a)) + Decimal(str(b)))
        logger.debug(f"加法运算: {a} + {b} = {result}")
        print(f"计算结果: {a} + {b} = {result}")
        return f"{result}"
    except Exception as e:
        logger.error(f"加法运算失败: {e}")
        return f"加法运算失败: {str(e)}"

@mcp.tool()
@performance_decorator
def subtract(a: float, b: float) -> str:
    """减法运算
    
    Args:
        a: 被减数
        b: 减数
        
    Returns:
        减法运算结果
    """
    try:
        validate_number(a, "被减数")
        validate_number(b, "减数")
        
        result = float(Decimal(str(a)) - Decimal(str(b)))
        logger.debug(f"减法运算: {a} - {b} = {result}")
        print(f"计算结果: {a} - {b} = {result}")
        return f"{result}"
    except Exception as e:
        logger.error(f"减法运算失败: {e}")
        return f"减法运算失败: {str(e)}"

@mcp.tool()
@performance_decorator
def multiply(a: float, b: float) -> str:
    """乘法运算
    
    Args:
        a: 第一个数字
        b: 第二个数字
        
    Returns:
        乘法运算结果
    """
    try:
        validate_number(a, "第一个数")
        validate_number(b, "第二个数")
        
        result = float(Decimal(str(a)) * Decimal(str(b)))
        logger.debug(f"乘法运算: {a} × {b} = {result}")
        print(f"计算结果: {a} × {b} = {result}")
        return f"{result}"
    except Exception as e:
        logger.error(f"乘法运算失败: {e}")
        return f"乘法运算失败: {str(e)}"

@mcp.tool()
@performance_decorator
def divide(a: float, b: float) -> str:
    """除法运算
    
    Args:
        a: 被除数
        b: 除数
        
    Returns:
        除法运算结果
    """
    try:
        validate_number(a, "被除数")
        validate_number(b, "除数")
        
        if b == 0:
            logger.warning("尝试除零操作")
            return "错误: 除数不能为零"
        
        result = float(Decimal(str(a)) / Decimal(str(b)))
        logger.debug(f"除法运算: {a} ÷ {b} = {result}")
        print(f"计算结果: {a} ÷ {b} = {result}")
        return f"{result}"
    except Exception as e:
        logger.error(f"除法运算失败: {e}")
        return f"除法运算失败: {str(e)}"

# ==================== 高级数学工具 ====================

@mcp.tool()
@performance_decorator
def power(base: float, exponent: float) -> str:
    """幂运算
    
    Args:
        base: 底数
        exponent: 指数
        
    Returns:
        幂运算结果
    """
    try:
        validate_number(base, "底数")
        validate_number(exponent, "指数")
        
        # 检查特殊情况
        if base == 0 and exponent < 0:
            return "错误: 0的负数次幂未定义"
        
        result = pow(base, exponent)
        logger.info(f"幂运算: {base}^{exponent} = {result}")
        return f"{base}^{exponent} = {result}"
    except Exception as e:
        logger.error(f"幂运算失败: {e}")
        return f"幂运算失败: {str(e)}"

@mcp.tool()
@performance_decorator
def square_root(number: float) -> str:
    """平方根运算
    
    Args:
        number: 被开方数
        
    Returns:
        平方根结果
    """
    try:
        validate_number(number, "被开方数")
        
        if number < 0:
            return "错误: 负数不能开平方根（实数范围内）"
        
        result = math.sqrt(number)
        logger.info(f"平方根运算: √{number} = {result}")
        return f"√{number} = {result}"
    except Exception as e:
        logger.error(f"平方根运算失败: {e}")
        return f"平方根运算失败: {str(e)}"

@mcp.tool()
@performance_decorator
def factorial(n: int) -> str:
    """阶乘运算
    
    Args:
        n: 非负整数
        
    Returns:
        阶乘结果
    """
    try:
        if not isinstance(n, int):
            return "错误: 阶乘的参数必须是整数"
        
        if n < 0:
            return "错误: 负数没有阶乘"
        
        if n > config.max_factorial:
            return f"错误: 数字过大，无法计算阶乘（最大值: {config.max_factorial}）"
        
        result = math.factorial(n)
        logger.info(f"阶乘运算: {n}! = {result}")
        return f"{n}! = {result}"
    except Exception as e:
        logger.error(f"阶乘运算失败: {e}")
        return f"阶乘运算失败: {str(e)}"

@mcp.tool()
@performance_decorator
def logarithm(number: float, base: float = math.e) -> str:
    """对数运算
    
    Args:
        number: 真数
        base: 底数（默认为自然对数e）
        
    Returns:
        对数结果
    """
    try:
        validate_number(number, "真数")
        validate_number(base, "底数")
        
        if number <= 0:
            return "错误: 真数必须大于0"
        if base <= 0 or base == 1:
            return "错误: 底数必须大于0且不等于1"
        
        if base == math.e:
            result = math.log(number)
            logger.info(f"自然对数运算: ln({number}) = {result}")
            return f"ln({number}) = {result}"
        elif base == 10:
            result = math.log10(number)
            logger.info(f"常用对数运算: log₁₀({number}) = {result}")
            return f"log₁₀({number}) = {result}"
        else:
            result = math.log(number, base)
            logger.info(f"对数运算: log_{base}({number}) = {result}")
            return f"log_{base}({number}) = {result}"
    except Exception as e:
        logger.error(f"对数运算失败: {e}")
        return f"对数运算失败: {str(e)}"

@mcp.tool()
@performance_decorator
def trigonometry(function: str, angle: float, unit: str = "radians") -> str:
    """三角函数运算
    
    Args:
        function: 三角函数名称 (sin, cos, tan, asin, acos, atan, sinh, cosh, tanh)
        angle: 角度值
        unit: 角度单位 ("radians" 或 "degrees")
        
    Returns:
        三角函数结果
    """
    try:
        validate_number(angle, "角度")
        
        # 角度单位转换
        if unit == "degrees":
            if function in ["sin", "cos", "tan", "sinh", "cosh", "tanh"]:
                angle_rad = math.radians(angle)
            else:
                angle_rad = angle
        else:
            angle_rad = angle
        
        # 计算三角函数
        functions = {
            "sin": math.sin,
            "cos": math.cos,
            "tan": math.tan,
            "asin": math.asin,
            "acos": math.acos,
            "atan": math.atan,
            "sinh": math.sinh,
            "cosh": math.cosh,
            "tanh": math.tanh
        }
        
        if function not in functions:
            return f"错误: 不支持的三角函数 '{function}'，支持的函数: {', '.join(functions.keys())}"
        
        # 反三角函数输入范围检查
        if function in ["asin", "acos"] and abs(angle) > 1:
            return f"错误: {function}的输入值必须在[-1, 1]范围内"
        
        result = functions[function](angle_rad)
        
        # 反三角函数结果单位转换
        if function in ["asin", "acos", "atan"] and unit == "degrees":
            result = math.degrees(result)
            unit_symbol = "°"
        else:
            unit_symbol = "°" if unit == "degrees" else ""
        
        logger.info(f"三角函数运算: {function}({angle}{unit_symbol}) = {result}")
        return f"{function}({angle}{unit_symbol}) = {result}"
    except Exception as e:
        logger.error(f"三角函数运算失败: {e}")
        return f"三角函数运算失败: {str(e)}"

# ==================== 统计分析工具 ====================

@mcp.tool()
@performance_decorator
def statistics_analysis(numbers: List[float]) -> str:
    """统计分析
    
    Args:
        numbers: 数字列表
        
    Returns:
        统计分析结果
    """
    try:
        if not numbers:
            return "错误: 数字列表不能为空"
        
        # 验证所有数字
        for i, num in enumerate(numbers):
            validate_number(num, f"第{i+1}个数字")
        
        # 计算统计量
        mean_val = statistics.mean(numbers)
        median_val = statistics.median(numbers)
        mode_val = None
        try:
            mode_val = statistics.mode(numbers)
        except statistics.StatisticsError:
            mode_val = "无唯一众数"
        
        stdev_val = statistics.stdev(numbers) if len(numbers) > 1 else 0
        variance_val = statistics.variance(numbers) if len(numbers) > 1 else 0
        
        result = {
            "数据个数": len(numbers),
            "平均值": round(mean_val, config.precision),
            "中位数": median_val,
            "众数": mode_val,
            "标准差": round(stdev_val, config.precision),
            "方差": round(variance_val, config.precision),
            "最小值": min(numbers),
            "最大值": max(numbers),
            "范围": max(numbers) - min(numbers)
        }
        
        logger.info(f"统计分析完成，数据个数: {len(numbers)}")
        return json.dumps(result, ensure_ascii=False, indent=2)
    except Exception as e:
        logger.error(f"统计分析失败: {e}")
        return f"统计分析失败: {str(e)}"

# ==================== 单位转换工具 ====================

@mcp.tool()
@performance_decorator
def unit_conversion(value: float, from_unit: str, to_unit: str, category: str) -> str:
    """单位转换
    
    Args:
        value: 要转换的数值
        from_unit: 源单位
        to_unit: 目标单位
        category: 单位类别 (length, weight, temperature, area, volume)
        
    Returns:
        转换结果
    """
    try:
        validate_number(value, "转换数值")
        
        # 单位转换表（转换为基本单位的系数）
        conversions = {
            "length": {  # 基本单位：米
                "mm": 0.001, "cm": 0.01, "m": 1, "km": 1000,
                "inch": 0.0254, "ft": 0.3048, "yard": 0.9144, "mile": 1609.34
            },
            "weight": {  # 基本单位：千克
                "mg": 0.000001, "g": 0.001, "kg": 1, "ton": 1000,
                "oz": 0.0283495, "lb": 0.453592
            },
            "temperature": {  # 特殊处理
                "celsius": "C", "fahrenheit": "F", "kelvin": "K"
            },
            "area": {  # 基本单位：平方米
                "mm2": 0.000001, "cm2": 0.0001, "m2": 1, "km2": 1000000,
                "inch2": 0.00064516, "ft2": 0.092903
            },
            "volume": {  # 基本单位：立方米
                "ml": 0.000001, "l": 0.001, "m3": 1,
                "gallon": 0.00378541, "quart": 0.000946353
            }
        }
        
        if category not in conversions:
            return f"错误: 不支持的单位类别 '{category}'，支持的类别: {', '.join(conversions.keys())}"
        
        category_units = conversions[category]
        
        # 温度转换特殊处理
        if category == "temperature":
            result = convert_temperature(value, from_unit, to_unit)
        else:
            if from_unit not in category_units or to_unit not in category_units:
                return f"错误: 单位 '{from_unit}' 或 '{to_unit}' 不在 {category} 类别中"
            
            # 转换为基本单位，再转换为目标单位
            base_value = value * category_units[from_unit]
            result = base_value / category_units[to_unit]
        
        logger.info(f"单位转换: {value} {from_unit} = {result} {to_unit}")
        return f"{value} {from_unit} = {result} {to_unit}"
    except Exception as e:
        logger.error(f"单位转换失败: {e}")
        return f"单位转换失败: {str(e)}"

def convert_temperature(value: float, from_unit: str, to_unit: str) -> float:
    """温度转换"""
    # 先转换为摄氏度
    if from_unit == "fahrenheit":
        celsius = (value - 32) * 5/9
    elif from_unit == "kelvin":
        celsius = value - 273.15
    else:  # celsius
        celsius = value
    
    # 从摄氏度转换为目标单位
    if to_unit == "fahrenheit":
        return celsius * 9/5 + 32
    elif to_unit == "kelvin":
        return celsius + 273.15
    else:  # celsius
        return celsius

# ==================== 表达式计算工具 ====================

@mcp.tool()
@performance_decorator
def calculate(expression: str) -> str:
    """计算数学表达式
    
    Args:
        expression: 数学表达式（支持复杂数学函数和常数）
        
    Returns:
        计算结果
    """
    try:
        # 验证表达式
        is_valid, message = validator.validate(expression)
        if not is_valid:
            logger.warning(f"表达式验证失败: {message}")
            return f"错误: {message}"
        
        # 创建安全的计算环境
        safe_dict = create_safe_math_environment()
        
        result = eval(expression, safe_dict)
        
        # 结果验证
        if math.isnan(result) or math.isinf(result):
            return "错误: 计算结果为NaN或无穷大"
        
        logger.info(f"表达式计算: {expression} = {result}")
        return f"{expression} = {result}"
    except ZeroDivisionError:
        logger.warning(f"表达式计算除零错误: {expression}")
        return "错误: 除零错误"
    except SyntaxError:
        logger.warning(f"表达式语法错误: {expression}")
        return "错误: 表达式语法不正确"
    except Exception as e:
        logger.error(f"表达式计算失败: {e}")
        return f"计算失败: {str(e)}"

@lru_cache(maxsize=128)
def create_safe_math_environment() -> Dict[str, Any]:
    """创建安全的数学计算环境"""
    return {
        "__builtins__": {},
        # 基础数学函数
        "abs": abs, "round": round, "min": min, "max": max,
        "sum": sum, "pow": pow,
        # 三角函数
        "sin": math.sin, "cos": math.cos, "tan": math.tan,
        "asin": math.asin, "acos": math.acos, "atan": math.atan,
        "atan2": math.atan2,
        # 双曲函数
        "sinh": math.sinh, "cosh": math.cosh, "tanh": math.tanh,
        "asinh": math.asinh, "acosh": math.acosh, "atanh": math.atanh,
        # 对数和指数函数
        "log": math.log, "log10": math.log10, "log2": math.log2,
        "exp": math.exp, "expm1": math.expm1, "log1p": math.log1p,
        # 幂和根函数
        "sqrt": math.sqrt, "cbrt": lambda x: x**(1/3),
        # 取整函数
        "floor": math.floor, "ceil": math.ceil, "trunc": math.trunc,
        # 其他数学函数
        "factorial": math.factorial, "gamma": math.gamma,
        "erf": math.erf, "erfc": math.erfc,
        # 角度转换
        "degrees": math.degrees, "radians": math.radians,
        # 数学常数
        "pi": math.pi, "e": math.e, "tau": math.tau, "inf": math.inf,
        # 统计函数（简化版）
        "mean": lambda *args: sum(args) / len(args),
        "median": lambda *args: sorted(args)[len(args)//2],
    }

# ==================== 系统工具 ====================

@mcp.tool()
def get_performance_stats() -> str:
    """获取性能统计信息
    
    Returns:
        性能统计数据
    """
    try:
        stats = monitor.get_stats()
        logger.info("获取性能统计信息")
        return json.dumps(stats, ensure_ascii=False, indent=2)
    except Exception as e:
        logger.error(f"获取性能统计失败: {e}")
        return f"获取性能统计失败: {str(e)}"

@mcp.tool()
def reset_performance_stats() -> str:
    """重置性能统计信息
    
    Returns:
        重置结果
    """
    try:
        global monitor
        monitor = PerformanceMonitor()
        logger.info("性能统计信息已重置")
        return "性能统计信息已重置"
    except Exception as e:
        logger.error(f"重置性能统计失败: {e}")
        return f"重置性能统计失败: {str(e)}"

# ==================== 资源定义 ====================

@mcp.resource("calculator://help")
def get_help() -> str:
    """获取计算器帮助信息"""
    return """🧮 MCP 高级计算器服务 v2.0 帮助文档

📊 基础运算工具:
1. add(a, b) - 加法运算
2. subtract(a, b) - 减法运算  
3. multiply(a, b) - 乘法运算
4. divide(a, b) - 除法运算

🔬 高级数学工具:
5. power(base, exponent) - 幂运算
6. square_root(number) - 平方根运算
7. factorial(n) - 阶乘运算
8. logarithm(number, base) - 对数运算
9. trigonometry(function, angle, unit) - 三角函数运算

📈 统计分析工具:
10. statistics_analysis(numbers) - 统计分析（均值、中位数、标准差等）

🔄 单位转换工具:
11. unit_conversion(value, from_unit, to_unit, category) - 单位转换
    支持类别: length, weight, temperature, area, volume

🧮 表达式计算:
12. calculate(expression) - 计算复杂数学表达式

⚙️ 系统工具:
13. get_performance_stats() - 获取性能统计
14. reset_performance_stats() - 重置性能统计

📝 使用示例:

基础运算:
- add(10, 5) → "10 + 5 = 15"
- divide(22, 7) → "22 ÷ 7 = 3.142857142857143"

高级数学:
- power(2, 10) → "2^10 = 1024"
- trigonometry("sin", 30, "degrees") → "sin(30°) = 0.5"
- logarithm(1000, 10) → "log₁₀(1000) = 3.0"

统计分析:
- statistics_analysis([1, 2, 3, 4, 5]) → 详细统计信息

单位转换:
- unit_conversion(100, "cm", "m", "length") → "100 cm = 1.0 m"
- unit_conversion(32, "fahrenheit", "celsius", "temperature") → "32 fahrenheit = 0.0 celsius"

表达式计算:
- calculate("sin(pi/2) + cos(0)") → "sin(pi/2) + cos(0) = 2.0"
- calculate("sqrt(16) + factorial(4) / 8") → "sqrt(16) + factorial(4) / 8 = 7.0"
- calculate("log10(1000) * pow(2, 3)") → "log10(1000) * pow(2, 3) = 24.0"

🔒 安全特性:
- 表达式长度限制和字符验证
- 危险模式检测
- 数值范围检查
- 高精度计算支持
- 完善的错误处理
- 性能监控和日志记录

📊 支持的数学函数和常数:
- 三角函数: sin, cos, tan, asin, acos, atan, atan2
- 双曲函数: sinh, cosh, tanh, asinh, acosh, atanh
- 对数函数: log, log10, log2, log1p
- 指数函数: exp, expm1
- 幂函数: pow, sqrt, cbrt
- 取整函数: floor, ceil, trunc, round
- 特殊函数: factorial, gamma, erf, erfc
- 数学常数: pi, e, tau, inf
- 统计函数: mean, median, min, max, sum
"""

if __name__ == "__main__":
    logger.info("MCP 高级计算器服务 v2.0 启动")
    mcp.run(transport="stdio")